﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;

namespace HeThongDoDien.IO
{
    #region Enumerations

    public enum DataTypeEnum
    {
        //None,
        Force,
        Distance,
    }

    public enum LogMsgTypeEnum
    {
        None,
        Incoming,
        Outgoing,
        Warning,
        Error,
    }
    #endregion

    /// <summary>
    /// Xử lý dữ liệu nhận được
    /// </summary>
    public delegate void DataIncomingHandler(object sender, byte[] data);

    public delegate void LogMsgHandler(object sender, LogMsgTypeEnum type, string message);

    /// <summary>
    /// COM Connector via RSC232
    /// </summary>
    public class RSC232Connector
    {

        #region Constructors
        public RSC232Connector()
        {
            this.m_str_portname = "COM1";
            this.m_int_baudrate = 9600;
            this.m_int_databits = 8;
            this.m_stopbits = StopBits.One;
            this.m_parity = Parity.None;
            this.m_sp_comport = new SerialPort();
        }

        public RSC232Connector(DataTypeEnum deviceType)
        {
            this.m_dt_device = deviceType;
        }

        ~RSC232Connector()
        {
            try
            {
                this.Close();
            }
            catch (Exception) { }
        }
        #endregion

        #region Local Fields
        /// <summary>
        /// The main control for communicating through the RS-232 port
        /// </summary>
        private SerialPort m_sp_comport;
        private string m_str_portname;
        private int m_int_baudrate;
        private int m_int_databits;
        private StopBits m_stopbits;
        private Parity m_parity;

        private DataTypeEnum m_dt_device;

        public string PortName
        {
            get { return m_str_portname; }
            set { m_str_portname = value; }
        }

        // Public Properties
        public int BaudRate
        {
            get { return m_int_baudrate; }
            set { m_int_baudrate = value; }
        }

        public int DataBits
        {
            get { return m_int_databits; }
            set { m_int_databits = value; }
        }

        public StopBits StopBits
        {
            get { return m_stopbits; }
            set { m_stopbits = value; }
        }

        public Parity Parity
        {
            get { return m_parity; }
            set { m_parity = value; }
        }

        #endregion

        #region Event Handler
        public event LogMsgHandler LogMsg;

        public event DataIncomingHandler DataIncoming;

        protected virtual void OnLogMsg(LogMsgTypeEnum type, string message)
        {
            if (LogMsg != null)
            {
                try
                {
                    LogMsg(this, type, message);
                }
                catch (Exception) { }
            }
        }

        protected virtual void OnDataIncoming(byte[] data)
        {
            if (DataIncoming != null)
            {
                try
                {
                    DataIncoming(this, data);
                }
                catch (Exception) { }
            }
        }
        #endregion

        #region IO Handler
        /// <summary>
        /// Send the binary data out the port
        /// </summary>
        public void Send(byte[] data)
        {
            if (data != null)
            {
                this.m_sp_comport.Write(data, 0, data.Length);
                OnLogMsg(LogMsgTypeEnum.Outgoing, data.Length.ToString());
            }
        }

        public void Close()
        {
            try
            {
                if (this.m_sp_comport.IsOpen == true)
                {
                    this.m_sp_comport.Close();
                    OnLogMsg(LogMsgTypeEnum.None, "Connection has been closed");
                }
            }
            catch (Exception ex)
            {
                OnLogMsg(LogMsgTypeEnum.Error, ex.Message);
                throw ex;
            }
        }

        public void Open()
        {
            if (this.m_sp_comport.IsOpen == true)
            {
                this.m_sp_comport.Close();
                this.m_sp_comport.Dispose();
            }
            // Setup
            this.m_sp_comport = new SerialPort();
            this.m_sp_comport.PortName = this.m_str_portname;
            this.m_sp_comport.BaudRate = this.m_int_baudrate;
            this.m_sp_comport.DataBits = this.m_int_databits;
            this.m_sp_comport.StopBits = this.m_stopbits;
            this.m_sp_comport.Parity = this.m_parity;
            this.m_sp_comport.DataReceived += new SerialDataReceivedEventHandler(m_sp_comport_DataReceived);
            this.m_sp_comport.PinChanged += new SerialPinChangedEventHandler(m_sp_comport_PinChanged);
            try
            {
                this.m_sp_comport.Open();
                var msg = string.Format("Connection has been openned. Port={0}, BaudRate={1}, DataBits={2}, StopBits={3}, Parity={4}", this.m_str_portname, this.m_int_baudrate, this.m_int_databits, this.m_stopbits, this.m_parity);
                OnLogMsg(LogMsgTypeEnum.Warning, msg);
            }
            catch (Exception ex)
            {
                OnLogMsg(LogMsgTypeEnum.Error, ex.Message);
                throw ex;
            }
        }

        private void m_sp_comport_PinChanged(object sender, SerialPinChangedEventArgs e)
        {
            //
        }

        private void m_sp_comport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // If the com port is openning, read data buffer
            if (this.m_sp_comport.IsOpen == true)
            {
                // This method will be called when there is data waiting in the port's buffer
                var dlen = this.m_sp_comport.BytesToRead;
                var dbuffer = new byte[dlen];
                this.m_sp_comport.Read(dbuffer, 0, dlen);
                OnDataIncoming(dbuffer);
            }
        }
        #endregion

        public override string ToString()
        {
            return this.m_str_portname;
        }
    }
}
